<?php

define('BRUNCE_ADD_EVENT',         1);
define('BRUNCE_GET_STATUS',        2);

function cobweb_getErrMsg($ierr)
{
	switch($ierr)
	{
		case  0:    return "Success";
		case -2:   return "Key is not exist";
		case -1:   return "System error";
		case -3:   return "input args is error";
		default:   return "Undefined error: $ierr";
	}
}

class COBWEB{
	var $sock;
        var $retry;
        var $port;
	function __construct($port = 7080, $retry = 3){
                $this->retry = $retry;
                $this->port = $port;
		$this->sock = @pfsockopen("localhost", $port, $errno, $errstr);
		if (!$this->sock) {
			error_log("ERROR: $errno - $errstr");
			return;
		}
		stream_set_timeout($this->sock, 1, 1000);
	} 

	function reconnect(){
                fclose($this->sock);
		$this->sock = @pfsockopen("localhost", $this->port, $errno, $errstr);
		if (!$this->sock) {
			error_log("ERROR: $errno - $errstr");
			return;
		}
		stream_set_timeout($this->sock, 1, 1000);
	} 

	function __destruct() { } 
	function graph( $user1, $user2){
		$ret = $this->inner_graph($user1, $user2); 
		$try = 0;
		while($ret === false && $try < $this->retry)
		{
			$ret = $this->inner_graph($user1, $user2); 
			$try++;
		}
		return $ret;
	}
/*
*/
	function infomation( $users){
		$ret = $this->inner_infomation($users); 
		$try = 0;
		while($ret === false && $try < $this->retry)
		{
			$ret = $this->inner_infomation($users); 
			$try++;
		}
		return $ret;
	}

	function friends( $user){
		$ret = $this->inner_friends($user); 
		$try = 0;
		while($ret === false && $try < $this->retry)
		{
			$ret = $this->inner_friends($user); 
			$try++;
		}
		return $ret;
	}
	function status(){
		$ret = $this->inner_status(); 
		$try = 0;
		while(!isset($ret['1'])  && $try < $this->retry)
		{
			$ret = $this->inner_status(); 
			$try++;
		}
		return $ret;
	}
	
	function reset( $arr){
		if(is_array($arr) && sizeof($arr) > 0)
		{
			$isize = sizeof($arr); 
			$input = "y\004".pack("I",$isize);
			foreach($arr as $k=>$v)
				$input .= pack("I",strlen($k)).$k;
			if(($wlen = fwrite($this->sock, $input)) <= 0 )
                        {
                            $this->reconnect();
                            return false;
                        }
			return true;
		}
		return false;
	}

	function inner_graph( $user1, $user2){
			$input = "y\003";
			$input .= pack("I",strlen($user1)).$user1;
			$input .= pack("I",strlen($user2)).$user2;
                      	if(($wlen = fwrite($this->sock, $input)) <= 0 )
                        {
                            $this->reconnect();
                            return false;
                        }

			$readlen = $READ = 102400;
			$response = fread($this->sock, $READ);
	                $arr = array();
              		if(isset($response{7}))
			{
				$sub = substr($response, 0, 8);
				$unpacked = unpack('I2',$sub);
				if(isset($unpacked['1']) && isset($unpacked['2']))
				{
					if($unpacked['2'] != 0)
                                        {
                                                error_log(cobweb_getErrMsg($unpacked['2'])); 
						return $unpacked['2'];
					}

					$left = $unpacked['1'] - strlen($response);
					while ( $left > 0 && !feof($this->sock) )
					{
						$contstr = fread ( $this->sock,  $left );
						if ( $contstr )
						{
							$response .= $contstr;
							$left -= strlen($contstr);
						}
					}

                                        //return errorcode;
					//echo "read = "; var_dump($response);
					$idx = 8;
					$sub = substr($response, $idx , 4);
					if(!isset($sub{3}))
					{
						error_log("get depth data error!");
						return false;
					}

					$unpacked = unpack('I',$sub);
					//echo "depth = "; var_dump($unpacked);
					$idx += 4;
					$depth = $unpacked['1'];
                                        if($depth == 0)
						return true;
					$sub = substr($response, $idx , 4);
					if(!isset($sub{3})){
						error_log("get items counts data error");
						return false;
					}

					$unpacked = unpack('I',$sub);
                                        $items = $unpacked['1'];
					//echo "items = "; var_dump($unpacked);
					$idx += 4;
                                       // $direct = $response[$idx];
                                       // $idx += 1;
					for($j = 0; $j <$items ; $j++)
					{
						$subarr = array();
						for($i=0; $i<$depth; $i++)
						{
							$str = substr($response, $idx, 4);
							if(!isset($str{3})){
								error_log("get one line friends data error");
								return false;
							}

							$unpacked = unpack('Iint', $str);
							$idx += 4;
							$subarr[$i] = substr($response, $idx, $unpacked['int']);
							$idx += $unpacked['int'];
						}
						if(sizeof($subarr) > 0)
							$arr[$j] = $subarr;
					}
                                        if(sizeof($arr) < $items)
                                             return false;
				}
			}
			else
				return false; //echo "return error!";
			return $arr;
	}

	function inner_infomation($users){
			$input = "y\006";
			if(!is_array($users))
			{
				echo "input is not array!\n";  
				return false;
			}                        
			$input .= pack("I",sizeof($users));
			foreach($users as $k=>$v)
				$input .= pack("I", strlen($k)).$k;
                        if(($wlen = fwrite($this->sock, $input)) <= 0 )
                        {
                            $this->reconnect();
                            return false;
                        }

			$readlen = $READ = 10240;
			$response = fread($this->sock, $READ);
	                $arr = array();
              		if(isset($response{7}))
			{
				$sub = substr($response, 0, 8);
				$unpacked = unpack('I2',$sub);
				if(isset($unpacked['1']) && isset($unpacked['2']))
				{
					if($unpacked['2'] != 0)
					{
                                                error_log(cobweb_getErrMsg($unpacked['2']));
                                        	return $unpacked['2']; // return errorcode;
                                        }

					$left = $unpacked['1'] - strlen($response);
					while ( $left > 0 && !feof($this->sock) )
					{
						$contstr = fread ( $this->sock,  $left );
						if ( $contstr )
						{
							$response .= $contstr;
							$left -= strlen($contstr);
						}
					}

					//echo "read = "; var_dump($response);
					$idx = 8;
					$sub = substr($response, $idx , 4);
					if(!isset($sub{3})){
						error_log("get friends counts data error!");
						return false;
					}

					$unpacked = unpack('I',$sub);
					//echo "counts = "; var_dump($unpacked);
					$idx += 4;
					$counts = $unpacked['1'];
					if($counts == 0)
						return $arr;
					for($j = 0; $j<$counts ; $j++)
					{ 
                                                /* ulen + uname  */
						$str = substr($response, $idx, 4);
						if(!isset($str{3})){
							error_log("get name length data error");
							return false;
						}
						$unpacked = unpack('Iint', $str);
						$idx += 4;
						$uname = substr($response, $idx, $unpacked['int']);
						$idx += $unpacked['int'];
                                                /* vlen + value */
						$str = substr($response, $idx, 4);
						if(!isset($str{3})){
							error_log("get value length data error");
							return false;
						}
						$unpacked = unpack('Iint', $str);
						$idx += 4;
						$value = substr($response, $idx, $unpacked['int']);
						$idx += $unpacked['int'];
						/* type  */ 
						$str = substr($response, $idx, 4);
						if(!isset($str{3})){
							error_log("get user type error");
							return false;
						}
						$unpacked = unpack('Iint', $str);
						$idx += 4;
						$arr[$uname] = array('_value'=>$value, '_num'=>$unpacked['int']);
					}
					if(sizeof($arr) < $counts)
						return false;
				}
			}
			else
				return false; //echo "return error!";
			return $arr;
	}
	
	function inner_friends( $user){
			$input = "y\001";
			$input .= pack("I",strlen($user)).$user;
                        if(($wlen = fwrite($this->sock, $input)) <= 0 )
                        {
                            $this->reconnect();
                            return false;
                        }
			$readlen = $READ = 10240;
			$response = fread($this->sock, $READ);
	                $arr = array();
              		if(isset($response{7}))
			{
				$sub = substr($response, 0, 8);
				$unpacked = unpack('I2',$sub);
				if(isset($unpacked['1']) && isset($unpacked['2']))
				{
					if($unpacked['2'] != 0)
					{
                                                error_log(cobweb_getErrMsg($unpacked['2']));
                                        	return $unpacked['2']; // return errorcode;
                                        }

					$left = $unpacked['1'] - strlen($response);
					while ( $left > 0 && !feof($this->sock) )
					{
						$contstr = fread ( $this->sock,  $left );
						if ( $contstr )
						{
							$response .= $contstr;
							$left -= strlen($contstr);
						}
						else
							return false;
					}

					//echo "read = "; var_dump($response);
					$idx = 8;
					$sub = substr($response, $idx , 4);
					if(!isset($sub{3})){
						error_log("get friends counts data error!");
						return false;
					}

					$unpacked = unpack('I',$sub);
					//echo "counts = "; var_dump($unpacked);
					$idx += 4;
					$counts = $unpacked['1'];
					if($counts == 0)
						return $arr;
					for($j = 0; $j<$counts ; $j++)
					{ 
                                                /* ulen + uname  */
						$str = substr($response, $idx, 4);
						if(!isset($str{3})){
							error_log("get firends name length data error");
							return false;
						}
						$unpacked = unpack('Iint', $str);
						$idx += 4;
						$uname = substr($response, $idx, $unpacked['int']);
						$idx += $unpacked['int'];
                                                /* vlen + value */
						$str = substr($response, $idx, 4);
						if(!isset($str{3})){
							error_log("get firends value length data error");
							return false;
						}
						$unpacked = unpack('Iint', $str);
						$idx += 4;
						$value = substr($response, $idx, $unpacked['int']);
						$idx += $unpacked['int'];
						/* type  */ 
						$str = substr($response, $idx, 4);
						if(!isset($str{3})){
							error_log("get user type error");
							return false;
						}
						$unpacked = unpack('Iint', $str);
						$idx += 4;
						$arr[$uname] = array('_value'=>$value, '_num'=>$unpacked['int']);
					}
					if(sizeof($arr) < $counts)
						return false;
				}
			}
			else
				return false; //echo "return error!";
			return $arr;
	}


	function inner_status(){
			$input = "y\005status";
                        if(($wlen = fwrite($this->sock, $input)) <= 0 )
                        {
                            $this->reconnect();
                            return false;
                        }
	
			$readlen = $READ = 1024;
			$response = fread($this->sock, $READ);
	                $arr = array();
              		if(isset($response{7}))
			{
				$sub = substr($response, 0, 8);
				$unpacked = unpack('I2',$sub);
				if(isset($unpacked['1']) && isset($unpacked['2']))
				{
					if($unpacked['2'] != 0)
						return false; // return errorcode;
				//	echo "read = "; var_dump($response);
					$idx = 8;
					$sub = substr($response, $idx , 12);
                                        if(!isset($sub{11}))
                                            return false;
					$arr = unpack('I3',$sub);
				}
				if(sizeof($arr)< 1)
					return false;
			}
			else
				return false; //echo "return error!";
			return $arr;
	}
}

for($i=1; $i<1000000; $i++)
{
	$obj = new COBWEB(11234);
	$ret = $obj->friends($i);
	var_dump($ret);
}
exit;


/*
$ret = $obj->infomation(array('1973'=>'', '2'=>''));
var_dump($ret);

$ret = $obj->graph('1973','12');
var_dump($ret);
*/
?>
